package com.linkdood.app.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jayway.jsonpath.JsonPath;
import com.linkdood.app.constants.ErrorCode;
import com.linkdood.app.constants.LinkDoodConstants;
import com.linkdood.app.domain.DoodOrganization;
import com.linkdood.app.domain.DoodUser;
import com.linkdood.app.domain.ThirdParty;
import com.linkdood.app.dto.DdioUserDTO;
import com.linkdood.app.exception.GeneralException;
import com.linkdood.app.exception.InvalidParamException;
import com.linkdood.app.service.DdioService;
import com.linkdood.app.service.ThirdPartyService;
import com.linkdood.app.service.TokenService;
import com.linkdood.app.service.ddio.*;
import com.linkdood.app.service.dto.DoodFriendsDTO;
import com.linkdood.app.utils.DdioUtil;
import com.linkdood.app.utils.PinYinUtil;
import com.linkdood.app.vm.AccountVM;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.http.HttpStatus;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;


/**
 * 该类封装了所有和 DDIO 交互的操作
 * 其他地方如果要使用 DDIO 相关的 API 必须通过该类来进行
 *
 * @author YunJ
 */
@Slf4j
@Service
public class DdioServiceImpl implements DdioService {

    public static final String PREFIX_HTTP = "http";

    private final ThirdPartyService thirdPartyService;

    private final TokenService tokenService;

    public DdioServiceImpl(ThirdPartyService thirdPartyService, TokenService tokenService) {
        this.thirdPartyService = thirdPartyService;
        this.tokenService = tokenService;
    }


    /**
     * 根据 code 从 ddio 获取登录用户信息
     * FIXME 该接口不在 ddio 校验内，因为无法获取到 code
     */
    @Override
    public DdioUserDTO doWithCode(String code) {
        ThirdParty thirdParty = thirdPartyService.getDefaultThirdParty();

        // 获取 oauth token 信息
        ResponseEntity<String> responseEntity = DdioUtil.getOauthTokenResponse(thirdParty, code);
        log.debug("OauthToken response = {}", responseEntity);
        String responseBody = responseEntity.getBody();
        if (StringUtils.isEmpty(responseBody)) {
            log.warn("有时候一次获取不到, 则再试一次");
            responseEntity = DdioUtil.getOauthTokenResponse(thirdParty, code);
            responseBody = responseEntity.getBody();
        }
        Integer responseCode = JsonPath.parse(responseBody).read("$.code");
        if (!Objects.equals(responseCode, 0)) {
            log.debug("token result : {}", responseBody);
            throw new InvalidParamException("code");
        }

        // 获取用户信息
        String token = JsonPath.parse(responseBody).read("$.result.token");

        ResponseEntity<String> getUserInfoResponseEntity = DdioUtil.getOauthUserInfoResponse(thirdParty, token);
        // 用户获取 accessToken 过期后，需要重新刷新 accessToken 需要调用豆豆提供的 刷新接口 获取新的 token
        log.debug("UserInfo response = {}", getUserInfoResponseEntity);
        Integer getUserInfoResponseCode = JsonPath.parse(responseBody).read("$.code");
        if (!Objects.equals(getUserInfoResponseCode, 0)) {
            log.warn("获取用户信息失败，刷新token再试一次");
            String freshToken = JsonPath.parse(getUserInfoResponseEntity).read("$.result.freshToken");

            ResponseEntity<String> freshAccessTokenResponseEntity = DdioUtil.getFreshAccessTokenResponse(thirdParty, freshToken);
            log.debug("freshAccessToken response = {}", freshAccessTokenResponseEntity);

            String accessToken = JsonPath.parse(freshAccessTokenResponseEntity.getBody()).read("$.result.accessToken");
            getUserInfoResponseEntity = DdioUtil.getOauthUserInfoResponse(thirdParty, accessToken);
        }

        responseCode = JsonPath.parse(getUserInfoResponseEntity.getBody()).read("$.code");
        if (!Objects.equals(responseCode, 0)) {
            throw new InvalidParamException();
        }

        LinkedHashMap<String, Object> userInfoResult = JsonPath.parse(getUserInfoResponseEntity.getBody()).read("$.result");
        log.debug("user info result : {}", userInfoResult.toString());
        return JSONObject.parseObject(JSONObject.toJSONString(userInfoResult), DdioUserDTO.class);
    }

    /**
     * 获取所有用户
     */
    @Override
    public List<DoodUser> listUsers(String thirdPartyId) {
        ThirdParty thirdParty = getThirdParty(thirdPartyId);
        List<DoodUser> result = new ArrayList<>();
        int pageNum = 1;
        int pageSize = 10;
        int count;
        try {
            do {
                ResponseEntity<String> response = DdioUtil.getAllUserResponse(thirdParty, tokenService.accessToken(thirdParty), pageNum, pageSize);
                DdioResponseBody resp = JSON.parseObject(response.getBody(), DdioResponseBody.class);
                if (null != resp && resp.getCode() == 0) {
                    log.debug("getAllUser result = {}", resp);
                    List<DoodUser> users = resp.getUserSet();
                    count = users.size();
                    result.addAll(users);
                } else {
                    log.error("getAllUser failed");
                    break;
                }
                pageNum++;
            } while (count > 0);
        } catch (Exception e) {
            log.error("{}", e);
        }
        return result;
    }

    /**
     * 获取用户 dood 好友
     */
    @Override
    public List<DoodFriendsDTO> listAllFriends(AccountVM userAccount) {
        AccountVM.InnerUser innerUser = userAccount.getUser();
        if (innerUser == null) {
            log.error("无法获取用户信息");
            return new ArrayList<>();
        }
        ThirdParty thirdParty = getThirdParty(innerUser.getThirdPartyId());
        List<DoodFriendsDTO> friends = new ArrayList<>();

        String userToken = innerUser.getSourceId();
        ResponseEntity<String> friendsResponse = DdioUtil.getAllBuddysResponse(thirdParty, userToken, tokenService.accessToken(thirdParty));
        Integer code = JsonPath.parse(friendsResponse.getBody()).read("$.code");
        if (!Objects.equals(code, 0)) {
            log.error("获取好友列表信息失败: {}", friendsResponse);
            return friends;
        }
        List<Object> friendResult = JsonPath.parse(friendsResponse.getBody()).read("$.result");
        friends = JSONObject.parseArray(JSONObject.toJSONString(friendResult), DoodFriendsDTO.class);

        // 处理好友头像, ddio 获取的头像地址没有包含域名端口信息 https://ghlyw.linkdood.cn:10077
        // 这里 thirdParty.getServerUrl() 确定有值
        String baseUrl = thirdParty.getServerUrl().split("platform")[0];
        if (!CollectionUtils.isEmpty(friends)) {
            for (DoodFriendsDTO friend : friends) {
                if (!StringUtils.isEmpty(friend.getPortraitUrl()) && !friend.getPortraitUrl().startsWith("http")) {
                    friend.setPortraitUrl(baseUrl + friend.getPortraitUrl());
                }

                // 设置首字母
                friend.setFirstPinYin(PinYinUtil.getFirstPinyin(friend.getName()));
            }
        }
        Collections.sort(friends);
        return friends;
    }

    /**
     * 获取所有的组织信息
     */
    @Override
    public List<DoodOrganization> listOrganizations(String thirdPartyId) {
        ThirdParty thirdParty = getThirdParty(thirdPartyId);
        List<DoodOrganization> organizations = null;
        try {
            ResponseEntity<String> responseEntity = DdioUtil.getAllOrgResponse(thirdParty, tokenService.accessToken(thirdParty));
            DdioResponseBody resp = JSONObject.parseObject(responseEntity.getBody(), DdioResponseBody.class);
            if (null != resp && resp.getCode() == 0) {
                log.debug("getAllOrg result = {}", resp);
                organizations = resp.getOrgList();
            } else {
                log.error("getAllOrg failed");
            }
        } catch (Exception e) {
            log.error("{}", e);
        }
        return organizations;
    }

    /**
     * 同步组织信息
     */
    @Override
    public List<DdioOrgSyncResponseBody.DdioSyncOrg> syncOrganizations(String thirdPartyId, String version) {
        ThirdParty thirdParty = getThirdParty(thirdPartyId);
        List<DdioOrgSyncResponseBody.DdioSyncOrg> result = new ArrayList<>();
        try {
            boolean continueSync = true;
            while (continueSync) {
                ResponseEntity<String> responseEntity = DdioUtil.getSyncOrgResponse(thirdParty, version, tokenService.accessToken(thirdParty));
                DdioOrgSyncResponseBody resp = JSONObject.parseObject(responseEntity.getBody(), DdioOrgSyncResponseBody.class);
                if (resp == null) {
                    log.error("getAllOrg failed");
                    break;
                }
                log.debug("getAllOrg result = {}", resp);
                if (CollectionUtils.isNotEmpty(resp.getResultList())) {
                    result.addAll(resp.getResultList());
                    version = String.valueOf(resp.getResultList().get(resp.getResultList().size() - 1).getChangeVersion());
                }
                continueSync = resp.isContinueSync();
            }
        } catch (Exception e) {
            log.error("sync organization failed : {}", e);
        }
        return result;
    }

    /**
     * 同步用户信息
     */
    @Override
    public List<DdioUserSyncResponseBody.DdioSyncUser> syncUsers(String thirdPartId, String version) {
        ThirdParty thirdParty = getThirdParty(thirdPartId);
        List<DdioUserSyncResponseBody.DdioSyncUser> result = new ArrayList<>();
        try {
            boolean continueSync = true;
            while (continueSync) {
                String token = tokenService.accessToken(thirdParty);
                ResponseEntity<String> responseEntity = DdioUtil.getSyncUserResponse(thirdParty, version, token);
                DdioUserSyncResponseBody resp = JSONObject.parseObject(responseEntity.getBody(), DdioUserSyncResponseBody.class);
                if (resp == null) {
                    log.error("getAllOrg failed");
                    break;
                }
                log.debug("getAllOrg result = {}", resp);
                if (CollectionUtils.isNotEmpty(resp.getResultList())) {
                    for (DdioUserSyncResponseBody.DdioSyncUser user : resp.getResultList()) {
                        // 调用获取基础信息拿头像信息
                        if (LinkDoodConstants.ACCESS_TYPE_CUSTOM_ACCOUNT.equals(thirdParty.getAccessType())) {
                            if (StringUtils.isEmpty(user.getAccount())) {
                                result.add(user);
                                continue;
                            }
                        }
                        ResponseEntity<String> userInfoResponse = DdioUtil.getUserInfoResponse(thirdParty, user, token);
                        Integer code = JsonPath.parse(userInfoResponse.getBody()).read("$.code");
                        String portraitUrl = "";
                        if (code == 0 && !StringUtils.isEmpty(userInfoResponse.getBody())) {
                            if (userInfoResponse.getBody().contains("\"headimgurl\"")) {
                                portraitUrl = JsonPath.parse(userInfoResponse.getBody()).read("$.result.headimgurl");
                                portraitUrl = getPortraitURL(portraitUrl, thirdParty.getServerUrl());
                            }
                            if (userInfoResponse.getBody().contains("\"sex\"")) {
                                Integer sex = JsonPath.parse(userInfoResponse.getBody()).read("$.result.sex");
                                if (sex != null) {
                                    user.setSex(sex.toString());
                                }

                            }
                            if (userInfoResponse.getBody().contains("\"orgID\"")) {
                                String orgId = JsonPath.parse(userInfoResponse.getBody()).read("$.result.orgID");
                                user.setOrgID(orgId);
                            }
                        }
                        user.setPortraitUrl(portraitUrl);
                        result.add(user);
                    }

                    version = String.valueOf(resp.getResultList().get(resp.getResultList().size() - 1).getChangeVersion());
                }
                continueSync = resp.isContinueSync();
                log.info("continueSync value = {}", continueSync);
            }
        } catch (Exception e) {
            log.error("sync uers failed : {}", e);
        }
        return result;
    }

    /**
     * 根据用户 id 获取详情
     *
     * @param userIds 用户 id
     * @return 豆豆用户详情
     */
    @Override
    public List<DoodUser> listUserInfoByUserIds(String[] userIds) {
        ThirdParty thirdParty = thirdPartyService.getDefaultThirdParty();
        ResponseEntity<String> responseEntity = DdioUtil.getUserInfoByIdsResponse(thirdParty, userIds, tokenService.accessToken(thirdParty));
        if (responseEntity.getStatusCodeValue() == HttpStatus.SC_OK) {
            DdioGeneralResponseBody responseBody = JSONObject.parseObject(responseEntity.getBody(), DdioGeneralResponseBody.class);
            List<DoodUser> doodUsers = null;
            if (responseBody.getCode() == 0) {
                doodUsers = JSONArray.parseArray(responseBody.getResult(), DoodUser.class);
            }

            if (CollectionUtils.isNotEmpty(doodUsers)) {
                doodUsers.forEach(doodUser -> doodUser
                    .setPortraitURL(getPortraitURL(doodUser.getPortraitURL(), thirdParty.getServerUrl())));
                return doodUsers;
            }
        }
        throw new GeneralException(ErrorCode.ERROR_DDIO);
    }

    /**
     * 获取公司配置信息
     */
    @Override
    public ThirdParty getThirdParty(String thirdPartyId) {
        ThirdParty thirdParty = thirdPartyService.getThirdParty(thirdPartyId);
        if (thirdParty == null) {
            throw new InvalidParamException("thirdPartyId");
        }
        return thirdParty;
    }

    private String getPortraitURL(String url, String appUrl) {
        String baseUrl = appUrl.split("platform")[0];
        if (!StringUtils.isEmpty(url) && !url.startsWith(PREFIX_HTTP)) {
            url = baseUrl + url;
        }
        return url;
    }

    /**
     * 发送消息
     */
    @Override
    public DdioResponseBody sendTemplate2Users(TemplateMessage templateMessage, String thirdId) {
        ThirdParty thirdParty = getThirdParty(thirdId);
        String url = DdioUtil.buildSendMessageUrl(thirdParty);
        HttpHeaders httpHeaders = DdioUtil.getHttpHeader(tokenService.accessToken(thirdParty));
        ResponseEntity<String> responseEntity = DdioUtil.sendMessage(url, templateMessage, httpHeaders);
        DdioResponseBody resp = JSONObject.parseObject(responseEntity.getBody(), DdioResponseBody.class);
        return resp;
    }
}
